package net.qiqbframework.spring.config;


import net.qiqbframework.commandhandling.CommandMessage;
import net.qiqbframework.config.Configurer;
import net.qiqbframework.config.ConfigurerModule;
import net.qiqbframework.eventhandling.EventMessage;
import net.qiqbframework.loadhanding.LoadMessage;
import net.qiqbframework.messaging.Message;
import net.qiqbframework.persisthanding.PersistMessage;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.Nonnull;
import java.util.List;


public class MessageHandlerConfigurer implements ConfigurerModule, ApplicationContextAware {

    private final Type type;
    private final List<String> handlerBeans;
    private ApplicationContext applicationContext;

    /**
     * @param type     The type of handler to register the beans as.
     * @param beanRefs A list of bean identifiers to register.
     */
    public MessageHandlerConfigurer(Type type, List<String> beanRefs) {
        this.type = type;
        this.handlerBeans = beanRefs;
    }

    @Override
    public void configureModule(@Nonnull Configurer configurer) {
        switch (type) {
            case EVENT:
                handlerBeans.forEach(handler -> configurer.registerEventHandler(c -> applicationContext.getBean(handler)));
                break;
            case COMMAND:
                handlerBeans.forEach(handler -> configurer.registerCommandHandler(c -> applicationContext.getBean(handler)));
                break;
            case PERSIST:
                handlerBeans.forEach(handler -> configurer.registerPersistHandler(c -> applicationContext.getBean(handler)));
                break;
            case LOAD:
                handlerBeans.forEach(handler -> configurer.registerLoadHandler(c -> applicationContext.getBean(handler)));
                break;
        }
    }

    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * Enumeration defining the auto configurable message handler types.
     */
    public enum Type {

        /**
         * Lists the message handler for {@link CommandMessage CommandMessages}.
         */
        COMMAND(CommandMessage.class),
        /**
         * Lists the message handler for {@link EventMessage EventMessages}.
         */
        EVENT(EventMessage.class),

        PERSIST(PersistMessage.class),

        LOAD(LoadMessage.class);


        private final Class<? extends Message<?>> messageType;

        // Suppressed to allow instantiation of enumeration.
        @SuppressWarnings({"rawtypes", "unchecked"})
        Type(Class<? extends Message> messageType) {
            this.messageType = (Class<? extends Message<?>>) messageType;
        }

        /**
         * Returns the supported {@link Message} implementation.
         *
         * @return The supported {@link Message} implementation.
         */
        public Class<? extends Message<?>> getMessageType() {
            return messageType;
        }
    }
}
